
#include <Inklude/ikCWebFormWinAPI.h>
//#include <Inklude/ikCThread.h>
#include <Inklude/ikCTimer.h>
#include <tbb/tbb_thread.h>

#pragma warning(disable : 4996)

using namespace std;
using namespace Inklude;

string URLEncoder::encode(string str) {
	int len = str.length();
	char* buff = new char[len + 1];
	strcpy(buff,str.c_str());
	string ret = "";
	for(int i=0;i<len;i++) {
		if(isOrdinaryChar(buff[i])) {
			ret = ret + buff[i];
		}else if(buff[i] == ' ') {
			ret = ret + "+";
		}else {
			char tmp[6];
			sprintf(tmp,"%%%x",buff[i]);
			ret = ret + tmp;
		}
	}
	delete[] buff;
	return ret;
}

bool URLEncoder::isOrdinaryChar(char c) {
	char ch = tolower(c);
	if(ch == 'a' || ch == 'b' || ch == 'c' || ch == 'd' || ch == 'e' 
		|| ch == 'f' || ch == 'g' || ch == 'h' || ch == 'i' || ch == 'j' 
		|| ch == 'k' || ch == 'l' || ch == 'm' || ch == 'n' || ch == 'o' 
		|| ch == 'p' || ch == 'q' || ch == 'r' || ch == 's' || ch == 't' 
		|| ch == 'u' || ch == 'v' || ch == 'w' || ch == 'x' || ch == 'y' 
		|| ch == 'z' || ch == '0' || ch == '1' || ch == '2' || ch == '3' 
		|| ch == '4' || ch == '5' || ch == '6' || ch == '7' || ch == '8' 
		|| ch == '9') {
		return true;
	}
	return false;
}

string URLDecoder::decode(string str) {
	int len = str.length();
	char* buff = new char[len + 1];
	strcpy(buff,str.c_str());
	string ret = "";
	for(int i=0;i<len;i++) {
		if(buff[i] == '+') {
			ret = ret + " ";
		}else if(buff[i] == '%') {
			char tmp[4];
			char hex[4];			
			hex[0] = buff[++i];
			hex[1] = buff[++i];
			hex[2] = '\0';		
			//int hex_i = atoi(hex);
			sprintf(tmp,"%c",convertToDec(hex));
			ret = ret + tmp;
		}else {
			ret = ret + buff[i];
		}
	}
	delete[] buff;
	return ret;
}

int URLDecoder::convertToDec(const char* hex) {
	char buff[12];
	sprintf(buff,"%s",hex);
	int ret = 0;
	int len = strlen(buff);
	for(int i=0;i<len;i++) {
		char tmp[4];
		tmp[0] = buff[i];
		tmp[1] = '\0';
		getAsDec(tmp);
		int tmp_i = atoi(tmp);
		int rs = 1;
		for(int j=i;j<(len-1);j++) {
			rs *= 16;
		}
		ret += (rs * tmp_i);
	}
	return ret;
}

void URLDecoder::getAsDec(char* hex) {
	char tmp = tolower(hex[0]);
	if(tmp == 'a') {
		strcpy(hex,"10");
	}else if(tmp == 'b') {
		strcpy(hex,"11");
	}else if(tmp == 'c') {
		strcpy(hex,"12");
	}else if(tmp == 'd') {
		strcpy(hex,"13");
	}else if(tmp == 'e') {
		strcpy(hex,"14");
	}else if(tmp == 'f') {
		strcpy(hex,"15");
	}else if(tmp == 'g') {
		strcpy(hex,"16");
	}
}

ikCWebFormWinAPI::ikCWebFormWinAPI() {
	string m_strContentType = "Content-Type: application/x-www-form-urlencoded";
	string m_strHostName = "localhost:8080";
	string m_strScriptFile = "";
	HINTERNET m_hSession = NULL;
	HINTERNET m_hConnect = NULL;
	HINTERNET m_hRequest = NULL;
	HINTERNET m_hResponse = NULL;
}
void ikCWebFormWinAPI::PutVariable(const char* VariableName,const char* Value) 
{
	if( !isDuplicateVar(VariableName) ) 
		/*string str = "Duplicate variable name - ";
		str = str + VariableName;
		throw ikCWebFormWinAPIException(str.c_str());
	}else {*/
    {
		m_vctVars.push_back(VariableName);
		m_vctVals.push_back(Value);
	}
}

string ikCWebFormWinAPI::GetVariable(const char* VariableName) const
{
	for(unsigned int i=0;i<m_vctVars.size();i++) {
		if(strcmpi(VariableName,m_vctVars[i].c_str()) == 0) {
			return m_vctVals[i];
		}
	}
	/*string str = "Variable not found - ";
	str = str + VariableName;
	throw ikCWebFormWinAPIException(str.c_str());*/
    std::string strDum;
    return strDum;
}

void ikCWebFormWinAPI::SetHost(const char* host) {
	m_strHostName = host;
}

void ikCWebFormWinAPI::SetScriptFile(const char* sf) {
	m_strScriptFile = sf;
}

string ikCWebFormWinAPI::GetHost() const {
	return m_strHostName;
}

string ikCWebFormWinAPI::GetScriptFile() const {
	return m_strScriptFile;
}

bool ikCWebFormWinAPI::SendRequest() {
    bool retVal = true;

    auto threadFunc = [&]()
    {
        string host;
        if (m_userName.size() > 0 && m_password.size() > 0)
        {
            host += "http://";
            host += m_userName.c_str();
            host += ":";
            host += m_password.c_str();
            host += "@";
        }

        host += m_strHostName;

	    string form_action = host + m_strScriptFile + "?";
	    int sz = m_vctVars.size();
	    for(int i=0;i<sz;i++) {
		    string var = m_vctVars[i];
	        string enc_var = URLEncoder::encode(var);
	        string val = m_vctVals[i];
	        string enc_val = URLEncoder::encode(val);
	        form_action = form_action + enc_var;
	        form_action = form_action + "=";
	        form_action = form_action + enc_val;
	        if(i != (sz-1)) {
		        form_action = form_action + "&";
		    }
        }   
	    m_hSession = InternetOpen(TEXT("ikikCWebFormWinAPI 1"),
                                    PRE_CONFIG_INTERNET_ACCESS,
                                    NULL,
                                    INTERNET_INVALID_PORT_NUMBER,
                                    0);
	    if(m_hSession == NULL) {
		    retVal = false;
	    }
        Inklude::ikCString tmpUrl;
        tmpUrl = form_action.c_str();
	    m_hRequest = InternetOpenUrl(m_hSession,
                                    tmpUrl.c_tstr(),
                                    NULL,
                                    0,
                                    INTERNET_FLAG_RELOAD,
                                    0);
        Reset();
	    if(m_hRequest == NULL) {
		    retVal = false;
	    }
    };
    tbb::tbb_thread _thread(threadFunc);
    _thread.join();
    Sleep(100);

    return retVal;
}

int ikCWebFormWinAPI::GetResponse(void* pBuffer, unsigned int sz, float fTimeOut) {

    int totalBytesRead = -1;
    bool isJobEnd = false;

    auto threadFunc = [&]()
    {
        totalBytesRead = 0;
        char* buff = (char*)pBuffer;

	    if(NULL != m_hRequest)
        {
            int origSize = sz;
	        std::string buffer;
            buffer.reserve(sz);
	        while (totalBytesRead < origSize) {
		        if (InternetReadFile(m_hRequest,buff,sz,&m_lBytesRead)) {
			        if (m_lBytesRead <= sz) {
				        /*throw ikCWebFormWinAPIException("Buffer overflow !");				
			        }*/
			            if (m_lBytesRead == 0)
				            break;
			            buff[m_lBytesRead] = 0;
			            buffer += buff;
			            strcpy(buff, "");
			            totalBytesRead += m_lBytesRead;
			            sz -= m_lBytesRead;
			            if (sz <= 0)
				            break;
                    }
		        }
	        }
	        strcpy(buff, buffer.c_str());
        }
        isJobEnd = true;
    };

    if (0.f == fTimeOut)
    {
        threadFunc();
    }
    else
    {
        tbb::tbb_thread _thread(threadFunc);
        _thread.join();
        ikCTimer timer;
        timer.Start();
        while (!isJobEnd && timer.ElapsedMilliseconds() < fTimeOut)
        {
            Sleep(100);
        }
    }


	return totalBytesRead;
}

unsigned long ikCWebFormWinAPI::GetBytesRead() 
{ 
    return m_lBytesRead; 
}

bool ikCWebFormWinAPI::isDuplicateVar(const char* var_name) {
	for(unsigned int i=0;i<m_vctVars.size();i++) {
		if(strcmpi(var_name,m_vctVars[i].c_str()) == 0) {
			return true;
		}
	}
	return false;
}

void ikCWebFormWinAPI::Reset()
{
    m_vctVars.clear();
    m_vctVals.clear();
}

void ikCWebFormWinAPI::SetUserName(const char* UserName)
{
    m_userName.clear();
    m_userName.assign(UserName);
}

void ikCWebFormWinAPI::SetPassword(const char* Password)
{
    m_password.clear();
    m_password.assign(Password);
}

ikCWebFormWinAPI::~ikCWebFormWinAPI() {
	if(m_hSession != NULL) InternetCloseHandle(m_hSession);
	if(m_hRequest != NULL) InternetCloseHandle(m_hRequest);	
};

